#ifndef F7C6A079_DF2D_4693_8FF9_D4AFA51D8062
#define F7C6A079_DF2D_4693_8FF9_D4AFA51D8062
#include<iostream>
#include"level.hpp"
#include<memory>
#include"message.hpp"
#include<ctime>
#include<sstream>
#include<vector>

namespace mian_yang
{
    class FormatItem
    {
    public:
        using ptr = std::shared_ptr<FormatItem>;
        virtual void format(std::ostream& out, LogMsg& msg) = 0;
    };

    class MsgFormatItem : public FormatItem
    {
    public:
        void format(std::ostream& out, LogMsg& msg) override
        {
            out << msg._payload;
        }
    };


    class LevelFormatItem : public FormatItem
    {
    public:
        void format(std::ostream& out, LogMsg& msg) override
        {
            out << LogLevel::toString(msg._level);
        }
    };
    class TimeFormatItem : public FormatItem
    {
    public:
        TimeFormatItem(const std::string& fmt = "%H:%M:%S")
        :_time_fmt(fmt)
        {}
        void format(std::ostream& out, LogMsg& msg) override
        {
            struct tm t;  //这个能够将时间戳保存
            localtime_r(&msg._ctime, &t);
            char tmp[32] = {0};
            strftime(tmp, 31, _time_fmt.c_str(), &t); //strftime能够将tm对象里面的时间以字符串中所给出的格式传到tmp里面。

            out << tmp;
        }
    private:
        std::string _time_fmt; //时间格式， %H 
    };
    class FileFormatItem : public FormatItem
    {
    public:
        void format(std::ostream& out, LogMsg& msg) override
        {
            out << msg._file;
        }
    };

    class LineFormatItem : public FormatItem
    {
    public:
        void format(std::ostream& out, LogMsg& msg) override
        {
            out << msg._line;
        }
    };
    class TidFormatItem : public FormatItem
    {
    public:
        void format(std::ostream& out, LogMsg& msg) override
        {
            out << msg._tid;
        }
    };
    class LoggerFormatItem : public FormatItem
    {
    public:
        void format(std::ostream& out, LogMsg& msg) override
        {
            out << msg._logger;
        }
    };
    class NLineFormatItem : public FormatItem
    {
    public:
        void format(std::ostream& out, LogMsg& msg) override
        {
            out << "\n";
        }
    };
    class TabFormatItem : public FormatItem
    {
    public:
        void format(std::ostream& out, LogMsg& msg) override
        {
            out << "\t";
        }
    };

    class OtherFormatItem : public FormatItem
    {
    public:
        OtherFormatItem(std::string str) : _str(str){}
        void format(std::ostream& out, LogMsg& msg) override
        {
            out << _str;
        }
    private: 
        std::string _str;
    };

    class Formatter
    {
    public:
        using ptr = std::shared_ptr<Formatter>;
        Formatter(const std::string& pattern = "[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n")
        : _pattern(pattern)
        {
            parsePattern();
        }

        
        //对msg进行格式化
        void format(std::ostream& out, LogMsg& msg)
        {
            for (auto& item : _items)
            {
                item->format(out, msg);
            }
        }
        std::string format(LogMsg& msg)
        {
            std::stringstream ss;
            format(ss, msg);
            return ss.str();    //这里返回一个对象
        }

        static void TestFormat()
        {
            mian_yang::LogMsg msg("main.cc", 12, "logger", "正在进行格式测试....", mian_yang::LogLevel::value::DEBUG);
            Formatter fmt("[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n");
            std::string str = fmt.format(msg);
            std::cout << str << std::endl;
        }

        private:

        //对格式化规则字符串进行解析
        bool parsePattern()
        {
            //1.对格式化规则字符串进行解析。ab%%cde[%d{%H:%M:%S}][%p]%T%m%n
            std::vector<std::pair<std::string, std::string>> fmt_order;
            size_t pos = 0;
            std::string key, val;
            while(pos < _pattern.size())
            {
                //1.处理原字符串--判断是否是%， 不是就是原始字符。
                if (_pattern[pos] != '%') //如果格式位置不是%， 就不是原%字符
                {
                    val.push_back(_pattern[pos++]);
                    continue;
                }
                
                //能走下来就代表pos位置就是%字符， %%称为处理一个原始%字符
                if (pos + 1 < _pattern.size() && _pattern[pos + 1] == '%')
                {
                    val.push_back('%');
                    pos += 2;
                    continue;
                }
                
                //能走下来， 代表%后面是一个格式化字符， 代表原始字符串处理完毕
                if (val.empty() == false)
                {
                    fmt_order.push_back(std::make_pair("", val));
                    val.clear();
                }

                //这时候pos指向的是%位置， 格式字符在西医阿哥位置
                pos += 1; //pos指向格式字符位置.
                if (pos == _pattern.size())
                {
                    std::cout << "%之后， 没有对应的格式化字符!\n";
                    return false;
                }
                key = _pattern[pos];
                pos += 1; //这个时候pos指向格式化字符之后的位置.
                if (pos < _pattern.size() && _pattern[pos] == '{')   //说明有子格式
                {
                    pos += 1;
                    while (pos < _pattern.size() && _pattern[pos] != '}')
                    {
                        val.push_back(_pattern[pos++]);
                    }
                    //走到了末尾跳出了循环， 则代表没有遇到}， 代表格式是错误的
                    if (pos == _pattern.size())
                    {
                        std::cout << "子规则{}匹配出错!\n";
                        return false;
                    }
                    pos += 1; //这个时候pos指向的是}位置， 向后走一步， 就走到了下次处理的新位置
                }
                fmt_order.push_back(std::make_pair(key, val));
                key.clear();
                val.clear();
            }

            //根据解析得到的数据初始化格式化子项数组成员

            for (auto& it : fmt_order)
            {
                _items.push_back(createItem(it.first, it.second));
            }

            return true;
        }



    private:
        FormatItem::ptr createItem(const std::string& key, const std::string& val)
        { 
            if (key == "d") return std::make_shared<TimeFormatItem>(val);
            if (key == "t") return std::make_shared<TidFormatItem>();       //线程这里不需要传参数
            if (key == "c") return std::make_shared<LoggerFormatItem>();     //打印日志器也不需要传参数
            if (key == "f") return std::make_shared<FileFormatItem>();        //文件不需要传参数  
            if (key == "l") return std::make_shared<LineFormatItem>();         //行号不需要传参数
            if (key == "p") return std::make_shared<LevelFormatItem>();
            if (key == "T") return std::make_shared<TabFormatItem>();
            if (key == "m") return std::make_shared<MsgFormatItem>();
            if (key == "n") return std::make_shared<NLineFormatItem>();
            if (key.empty()) return std::make_shared<OtherFormatItem>(val);
            std::cout << "没有对应的字符串" << std::endl;
            abort();

            return FormatItem::ptr();
        }




    private:
        std::string _pattern;     //格式
        std::vector<FormatItem::ptr> _items;
    };

}

#endif /* F7C6A079_DF2D_4693_8FF9_D4AFA51D8062 */


